home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-05-20 | 96.5 KB | 3,116 lines |
-
-
-
-
-
-
-
-
-
-
-
-
-
- CDB
-
-
- Copyright (C) 1991 by Daytris
- All rights reserved
-
-
-
- Revised: May 20th, 1991
-
-
- INTRODUCTION
-
-
- Overview
-
- CDB is a sophisticated database toolkit for MS-DOS and UNIX
- developers. CDB includes the following features:
-
- - Quick data access through a sophisticated multi-key ISAM
- implementation.
-
- - Multiple data models. Both relational and network data
- models are implemented in CDB. The network model gives the
- developer the ability to create relationships between
- records without storing unique keys in those records.
-
- - Data Definition Language (DDL) for defining database layouts.
- The DDL is compiled into a binary format which is used by the
- database server as a roadmap. Using this concept, a
- developer can define and re-define a database with minimal
- effort and absolutely no code changes. The DDL is patterned
- after C for ease of programming.
-
- - Over 30 predefined database function calls for complete
- control of the database.
-
- - Portability. CDB is written entirely in C for portability
- and source code is included with your purchase. A version
- of CDB is also available for the MS-Windows platform.
- Contact the developers for more information about this
- product.
-
- - C++ compatibility. The library is callable from both C and
- C++.
-
- - Automatic re-use of deleted database space. There is no need
- for database reorganization. Deleted space is automatically
- reused by CDB.
-
- - Low overhead. The CDB database engine requires an extremely
- small amount of memory to operate.
-
- - Royalty-free distribution rights. Whether you have one
- customer or thousands, you pay for CDB just once for each
- environment that you are using.
-
-
- Obtaining CDB
-
- Refer to the document included in this release, ORDER.TXT, to order
- CDB. Your purchase will include CDB libraries, utilities, royalty-
- free use of library functions, full library and utility source code
- and make files. A printed manual will also be included.
-
-
- Future Enhancements
-
- Listed below are some of the enhancements planned for CDB. Any
- suggestions would also be greatly appreciated.
-
- - Multi-user database access. Networks and/or protocols to be
- supported are currently undefined.
-
- - Performance enhancements.
-
-
- Contacting the Developers
-
- CDB was developed solely by Daytris. If you have a question about
- the product or any suggestions please contact us at the phone
- number listed below. Or if you prefer, you can send us electronic
- mail on any of the information services listed.
-
- Daytris
- 81 Bright Street, Suite 1E
- Jersey City, NJ 07302
- 201-200-0018
-
- CompuServe: 72500,1426
- BIX: daytris
- GEnie: t.fearn
-
-
- GETTING STARTED
-
-
- Unpacking
-
- CDB is distributed in self-extracting ZIP files. When you first
- unpack your software, you may want to verify that you have a
- complete set. If you have the Test Drive version, you should have
- the files included in CDB.EXE. If you have purchased CDB, you
- should have the files included in both CDB.EXE and CDBSRC.EXE.
- The contents of each are listed below.
-
- CDB.EXE
-
- File Name Description
- --------- -----------
-
- CDB.TXT This document.
- ORDER.TXT Order form for CDB.
- REGISTER.TXT Registration form for CDB.
- README.TXT Latest CDB info.
- UPDATES.TXT History of updates made to CDB.
- MSCCDBL.LIB CDB library. Microsoft C large model.
- TCCDBL.LIB CDB library. Turbo C large model.
- DBDLIST.EXE Database Definition (DBD) file display
- utility.
- DDLP.EXE Database Definition Language Parser.
- TEST.C TEST do nothing program.
- TEST.DDL TEST Data Definition Language File.
- DBMGR.H CDB header file.
- MSCTEST.MAK Make file for TEST (Microsoft C).
- Microsoft NMAKE and UNIX make compatible.
- TCTEST.MAK Make file for TEST (Turbo C). Microsoft
- NMAKE and UNIX make compatible.
-
-
- CDBSRC.EXE
-
- File Name Description
- --------- -----------
-
- LICENSE.TXT Daytris software license agreement.
- MSCLIB.MAK Library make file (Microsoft C).
- Microsoft NMAKE and UNIX make compatible.
- TCLIB.MAK Library make file (Turbo C). Microsoft
- NMAKE and UNIX make compatible.
- DBADD.C Library source file.
- DBUPD.C .
- DBDEL.C .
- DBFIND.C .
- DBGET.C .
- DBCURR.C .
- DBFILE.C .
- DBMGR.C .
- DBPAGE.C .
- DBSLOT.C .
- DBTALK.C .
- DBFUNCS.C .
- DBMGR.H CDB header file.
- DBXTRN.H External definitions header file.
- STDINC.H Header file that includes other header
- files used in CDB.
- DDLP.MAK Make file for DDLP. Microsoft NMAKE and
- UNIX make compatible.
- MAIN.C DDLP source file.
- DDLP.C .
- PARSE.C .
- ERROR.C .
- DDLP.H DDLP header file.
- DBDLIST.MAK Make file for DBDLIST. Microsoft NMAKE and
- UNIX make compatible.
- DBDLIST.C DBDLIST source file.
-
-
- THE NETWORK DATABASE MODEL
-
-
- Introduction
-
- CDB provides both relational and network model features. The use
- of both models in a data design can greatly increase the
- performance of your database. For those of you who are already
- familiar with the relational database concepts, you will find the
- network model implementation very refreshing. For those of you
- who aren't familiar with the relational model, a very brief
- description of relational concepts follows.
-
-
- The Relational Model
-
- In a relational database, data is stored in a series of tables.
- Each table consists of a number of columns, which identify a
- particular type of data, and rows, which correspond to a particular
- record in the table.
-
- Individual records can be retrieved using the key fields defined
- for the table. If the developer has the desire to make an
- association between two tables, unique key fields must be defined
- in both records and unique data must be stored for retrieval to
- take place.
-
-
- What is the Network Model?
-
- This model allows you to define relationships between records
- through constructs called sets. A set defines a one-to-many
- relationship between two tables.
-
- In a relational model, records can only be related (connected)
- by storing unique keys in both tables. This method creates
- additional unwanted overhead. Duplicate data is stored in both
- records and duplicate indexes must be managed.
-
- Using the network model, records are connected by directly storing
- data pointers inside the record. Where the relational model
- requires multiple disk accesses to locate a related record, the
- network model allows the record to be located in a single disk
- access. Disk space is also saved when sets are used because no
- index is required.
-
- Another advantage of using the network model is the flexibility
- of owner/member relationships. A record may own multiple record
- types. A record may also be owned by multiple owner records. An
- example of this would be a 'client' record owning 'invoice'
- records and also owning 'address' records. In turn, an 'invoice'
- could also own 'address' records, perhaps a shipping and billing
- address. This kind of flexibility gives the developer the power
- to define complex data relationships with relative ease.
-
-
- THE DATA DEFINITION LANGUAGE
-
- Introduction
-
- The Data Definition Language is used for defining a database model.
- The language is basically a superset of C structure definitions.
- If you are familiar with defining C structures, the DDL should be
- very easy to pick up on.
-
- The DbOpen function call loads a binary image of a DDL file. The
- binary image is created by compiling the DDL file into a DBD
- (Database Definition) format. A DDL compiler is included with this
- release, DDLP.EXE (Data Definition Language Parser).
-
-
- An Example:
-
- /* sampledb.ddl */
-
- prefix ABC;
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char sate[3];
- key char zip[11];
- key char telephone[13];
- char fax[13];
- };
-
- struct setup
- {
- key long nextclientnbr;
- };
-
-
- Notice the close resemblence to C structure definitions. The only
- differences are the prefix, connect, and key words.
-
-
-
- prefix
-
- The prefix is used internally by the database library when a new
- database file must be created. In the SAMPLEDB.DDL shown above,
- the prefix is "ABC". By defining the prefix as "ABC", we are
- telling the library to use "ABC" as the first 3 characters of any
- file that is created for the SAMPLEDB database.
-
- The prefix can be from 1 to 4 characters in length. If a prefix is
- not defined, a default prefix, "TEST", is used.
-
- For more information about the CDB database file naming
- conventions, refer to the 'Database File Names' section in this
- manual.
-
-
- connect
-
- When using the connect keyword, you are taking advantage of the
- network database model implementation of CDB. Network model
- concepts can greatly increase the performance and efficiency of
- your database.
-
- The connect keyword defines a relationship between two records.
-
- struct client
- {
- connect address key street;
- .
- .
- };
-
- In this example, we are defining a relationship between the client
- record and the address record. The client record will be an owner
- of the address record. The address record is a member of the
- client record. For now, ignore the 'key street' part of the
- connect phrase.
-
- By declaring this set relationship, we now have the capability to
- make connections between client and address records using the
- DbSet... function calls. A client may own 0, 1 or many address
- records. Without the network model concepts that we have just
- shown you, to make connections between two records would require
- the storage of a unique key in each individual record.
-
- void Function()
- {
- static CLIENT client = {1000L,"Daytris","A software company",
- 0.00};
- static ADDRESS address = {"81 Bright Street, Suite 1E",
- "Jersey City","NJ","07302","201-200-0018",""};
-
- DbRecordAdd( "client", &client);
- DbRecordAdd( "address", &address);
- DbSetAdd( "client", "address");
- }
-
-
- The example above shows how to make a set connection between two
- records by using the DbSetAdd function. After the function call,
- the client "Daytris" is the owner of 1 address record. This
- address record can be retrieved using the DbSetGetFirst call:
-
- DbSetGetFirst( "client", "address", &address);
-
-
- Now lets add another address record to the set:
-
- void Function()
- {
- long key = 1000L;
- static ADDRESS address = {"30 Broad Street","New York","NY",
- "10015","212-555-1212","212-555-1212"};
-
- /* Make client #1000 current */
- DbRecordFindByKey( "client", "clientnbr", &key);
-
- /* Add another member */
- DbRecordAdd( "address", &address);
- DbSetAdd( "client", "address");
- }
-
- The client "Daytris" now owns 2 address records. We can use the
- DbSetGetFirst, DbSetGetLast, DbSetGetNext, or DbSetGetPrev to
- retrieve any of the address records in the set.
-
- Now lets take a look at how the sets are ordered. If we make a
- DbSetGetFirst call after adding the sets shown above, which address
- record would be returned? Lets return to our original DDL example:
-
- struct client
- {
- connect address key street;
- .
- .
- };
-
- Member records can be ordered two ways. By the order in which they
- are added, or by a field in the member record. In our example, the
- set order is by the street field in the address record. Therefore,
- a DbSetGetFirst( "client", "address", ...) call would return the
- "30 Broad Street" address record. If the connect address phrase
- were defined without a key:
-
- struct client
- {
- connect address;
- .
- .
- };
-
-
- the address members would be stored in the order that they were
- added. Therefore, a DbSetGetFirst( "client", "address", ...)
- call would return the "81 Bright Street, Suite 1E" address because
- this address was added first.
-
- A record can have more than one member. A record can also be owned
- by more than one owner. To illustrate this, lets take the
- SAMPLEDB.DDL and expand it to include invoicing capabilities.
-
- /* sampledb.ddl - with invoicing */
-
- prefix ABC;
-
- struct client
- {
- connect address key street;
- connect invoice;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char state[3];
- key char zip[11];
- key char telephone[13];
- char fax[13];
- };
-
- struct invoice
- {
- connect address;
- connect invoiceline;
- key long invoicenbr;
- long date;
- double totalprice;
- };
-
- struct invoiceline
- {
- long quantity;
- char description[31];
- double unitprice;
- double lineprice;
- };
-
- struct setup
- {
- key long nextclientnbr;
- long nextinvoicenbr;
- };
-
-
- In this example, a client record can own multiple address records
- and multiple invoice records. This makes sense because a client
- could have more than one address, i.e. a shipping and billing
- address. The client could also have more than one invoice if more
- than one order is placed.
-
- Also in this example, an owner/member relationship exists between
- the invoice and address records. If our invoice has both 'ship to'
- and 'bill to' addresses, the shipping address could be stored as
- the first member in the set and the billing address could be stored
- as the next member.
-
- A variable number of line items could exist on an invoice. This is
- the reason for the invoiceline record and its relationship with the
- invoice. An invoice record will own its invoice lines.
-
- The following example illustrates how all data pertaining to a
- specific invoice might be retrieved. Note: it is suggested that
- the CDB return values be taken more seriously than illustrated
- below.
-
- typedef struct invoice INVOICE;
- typedef struct invoiceline INVOICELINE
- typedef struct client CLIENT;
- typedef struct address ADDRESS;
-
-
- void Function()
- {
- long key = 2000L;
- UINT status;
- INVOICE invoice;
- INVOICELINE invoiceline;
- CLIENT client;
- ADDRESS shipaddress;
- ADDRESS billaddress;
-
- /* Get invoice #2000 */
- DbRecordGetByKey( "invoice", "invoicenbr", &invoice, &key);
-
- /* Get the client that owns the invoice */
- DbSetGetOwner( "client", "invoice", &client);
-
- /* Get the 'ship to' and 'bill to' addresses */
- DbSetGetFirst( "invoice", "address", &shipaddress);
- DbSetGetNext( "invoice", "address", &billaddress);
-
- /* Retrieve all invoice lines (assuming at least 1 line) */
- status = DbSetGetFirst( "invoice", "invoiceline", &invoiceline);
- while( status != E_NONEXT && status != E_NOTFOUND)
- {
- /* Store the line */
-
- /* Get the next line */
- status = DbSetGetNext( "invoice", "invoiceline",
- &invoiceline);
- }
- }
-
- This example illustrates some of the capabilities that you have
- with set relationships. The possibilities are endless.
-
-
- key
-
- The key word is used for defining key fields in records and key
- fields to be used in set relationships. See the connect section
- directly preceding this section for more details about the key
- fields in set relationships.
-
- Key fields are stored in ascending order in slots on pages in a
- key file. The key file is made up of a series of linked pages.
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- char name[31];
- char description[61];
- double balance;
- };
-
-
- This DDL structure definition contains only one key field,
- "clientnbr". Therefore all pages in the corresponding key file
- will contain will contain slots of sorted client numbers.
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- The DDL structure definition now contains two key fields,
- "clientnbr" and "name". Therefore two types of key pages will
- exist in the key file for this record type. Some pages will
- contain slots of sorted client numbers and other pages will contain
- slots of sorted client names. The data stored on the key file
- pages is directly related to the number of key fields defined in
- the DDL file.
-
- To maximize the efficiency of your database, it is suggested that
- you use as few key fields as possible. The maximum number of key
- fields allowed in a record is defined as MAXKEY in DBMGR.H. It is
- currently set to 8. See 'Modifying the Database Internals' section
- for more information about MAXKEY.
-
- If a structure is defined without a key field, the only way to
- access a record of this type is with a set relationship. The
- structure defined without a key field must be a member of another
- record.
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char state[3];
- char zip[11];
- char telephone[13];
- char fax[13];
- };
-
- In this example, the address record contains no key fields.
- Therefore, the address record cannot be accessed using any
- DbRecord... function calls because these functions require a key
- field as a parameter. However, the address is a member of the
- client record. Therefore, it could be accessed with the
- DbSetGet... function calls, provided a relationship exists.
-
-
- DDL Limitations
-
- The Data Definition Language does not currently support the
- definition of structures or unions defined from within a structure.
- Example:
-
- struct client
- {
- struct address addr;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- These deficiencies will be supported in a later release of CDB.
- A way to get around this problem for now is to allocate enough
- space as a char field for the structure or union that could not be
- included. Example (assuming the address structure length is 92
- bytes):
-
- struct client
- {
- char addr[92];
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- After DDLP compilation, modify the C header file output by DDLP to
- include the proper structure definition.
-
-
- DATABASE CURRENCY
-
-
- What is Currency?
-
- Currency refers to the record position in a database key file. It
- is very similiar to the file pointer in an open file. For example,
- when you first open a file using the C run-time library "open"
- function, the file pointer points to the first byte in the file
- (it could point to the last byte depending on how its opened).
- After the file is open, you can seek to different positions in the
- file and read or write data. The file pointer position is kept
- internally by the operating system. You could think of this
- position as the current position or "currency".
-
- In CDB, the concepts are very similar. Each record structure
- defined in a DDL will have an associated currency table when this
- database is opened.
-
-
- An Example:
-
- /* sampledb.ddl */
-
- prefix ABC;
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char state[3];
- key char zip[11];
- key char telephone[13];
- char fax[13];
- };
-
- struct setup
- {
- key long nextclientnbr;
- };
-
-
- When this database is opened using DbOpen, 3 currency tables will
- be initialized to zero. One for each record type: 'client',
- 'address', and 'setup'. The currency table contains the following
- format:
-
- struct currency_index
- {
- struct
- {
- UINT page;
- UINT slot;
- } keydba[MAXKEY]; /* Array of key dba's */
- ULONG datadba; /* Data database address */
- };
-
-
- keydba
-
- The currency table consists of two parts; a key currency (keydba)
- and a data record currency (datadba). A keydba exists for each
- key defined in the record table. In the example defined above,
- the 'client' record would use the first two keydba structures in
- the currency_index table for key currency storage. Records that
- do not have any keys defined would not make use of the keydba part
- of the currency_index.
-
- Lets say that we have three 'client' records in our database. The
- contents of each are as follows:
-
- Record 1: 1000L,"Daytris","Software Development",0.00
- Record 2: 1001L,"Microsoft","Software Development",10000.00
- Record 3: 1002L,"CompuServe","Computer Services",100.00
-
- When the database is opened, the currency_index for the 'client'
- record, as well as all other records, is null. In other words,
- "the client record does not have currency". If we were to issue a:
-
- DbRecordFindNext( "client", "clientnbr");
-
- at this time, an E_NONEXT return value would result. There is no
- next record to find! However, if we were to issue a:
-
- DbRecordFindFirst( "client", "clientnbr");
-
- the return value would be 0 indicating a successful call. After
- this call, the keydba structure within the currency_index for the
- 'client' record would contain the appropriate page and slot number
- of the first record for the "clientnbr" index. In this case, the
- keydba[0] structure within the 'client' currency_index would point
- to client number 1000L, Daytris.
-
- If we were to now issue a:
-
- DbRecrordFindNext( "client", "clientnbr");
-
- the keydba[0] structure within the 'client' currency_index would
- point to the next client sorted by "lClientNbr". In our example,
- it would point to 1001L, Microsoft.
-
- Keep in mind that we are not retrieving any records, we are only
- setting currency for the 'client' record type. If we would want
- to retrieve a record, we would use the DbRecordGet... function
- calls. Using the DbRecordFind... function calls we can essentially
- "seek" to positions within the database based on any index field
- within a record type.
-
-
- datadba
-
- The datadba field in the currency_index is used for "set" currency.
- When we issue a DbSetFind.. function call, the datadba is used to
- locate the current set record. The datadba field contains the
- actual slot number of the current record. "Next" and "previous"
- set pointers are stored at the beginning of each data slot in a
- data file.
-
-
- Differences Between Find and Get Function Calls
-
- The DbRecordFind... and DbSetFind... function calls only set
- currency for a specific record type. They do not retrieve records.
- You may want to think of the Find function calls as performing the
- same task as the C run-time lseek function. Essentially, we are
- seeking to a position in the database.
-
- If you wish to retrieve a record, use the DbRecordGet... or the
- DbSetGet... function calls. Note: The DbRecordGet... and
- DbSetGet... function calls call their Find counterparts first, and
- then retrieve the current record. For example, the
- DbRecordGetFirst function will perform a DbRecordFindFirst and then
- a DbRecordGetCurrent function call.
-
-
- Storing Currency Tables
-
- You can retrieve a copy of the current currency_index for each
- record defined in the DDL. Why would you want to do this?
-
- Lets suppose that you have a database that contains hundreds of
- 'client' records. Your application must be able to display these
- 'client' records in a small window, but you don't have enough
- memory to keep all of the 'client' records resident. Or it may
- be a waste of memory to do so. This is where storing currency
- tables becomes necessary.
-
- As previously explained, each record type defined in a DDL has an
- associated currency table. The contents of a currency table can
- be retrieved or updated at any time. Therefore, in the example
- explained above, we could retrieve a window of 'client' records
- along with their associated currency_index tables. Example:
-
-
- UINT GetWindowOfClients( BOOL bFirstTime)
- {
- register short i;
- UINT status;
- struct currency_index currency;
-
- for( i=0 ; i<WINDOW_LINES ; i++)
- {
- /* Get the record */
- if( bFirstTime)
- {
- bFirstTime = FALSE;
- status = DbRecordGetFirst( "client", "clientnbr",
- &client);
- }
- else
- status = DbRecordGetNext( "client", "clientnbr",
- &client);
- if( status)
- return status;
-
- /* Get the currency table */
- status = DbRecordGetCurrency( "client", ¤cy);
-
- /* Put the record in a window and store along with it
- the associated currency table */
- }
- }
-
- After calling this routine, we have a window of 'client' records.
- For each 'client' record we also have an associated currency table.
- If the user were to select a specific 'client' in the window, we
- could retrieve this 'client' with the following database calls:
-
- DbRecordUpdCurrency( "client", ¤cy);
- DbRecordGetCurrent( "client", "clientnbr", &client);
-
- The "currency" structure passed in the DbRecordUpdCurrency call
- represents the currency_index of the selected 'client' record.
- Because we have a currency table stored for each 'client' record
- in the window, we can retrieve any record in the window using
- this method.
-
-
- Deleting a current record
-
- Beware when deleting a current record. If you are storing a
- series of currency tables as we have done in the example explained
- above, deleting a current record will invalidate currency tables
- that followed this record. Suppose we have a window of 'client'
- records:
-
- Record 1: 1010L,"ABC Corp.","Diskette Manufacturer",0.00
- Record 2: 1011L,"XYZ Corp.","Hard Drive Manufacturer",0.00
- Record 3: 1012L,"BYTE Magazine","Software Publication",0.00
- Record 4: 1013L,"Sharp","Electronics",0.00
- Record 5: 1014L,"Collins","Radio Electronics",0.00
-
- We have also stored currency tables associated with each 'client'
- record in the window.
-
- If for example we delete Record 2, "XYZ Corp.", the currency
- tables associated with Records 3, 4, and 5 will now be invalid.
- Remember that currency tables contain the page and slot of a data
- item. If a record is deleted, the key fields are removed from
- their associated pages. The data (slots) on a key page are
- compressed to be contiguous. Therefore, key fields stored after
- the deleted record will be moved up 1 slot. Or possibly, if the
- slot is the last slot on a page, the page will be removed entirely.
-
- To avoid retaining invalid currency tables in memory after deleting
- a record, currency tables should be re-retrieved after the deletion.
- To do this, start the retrieval with the record before the deleted
- record. In the example above, Record 2 is being deleted. After
- the deletion, restore the Record 1 currency table (using
- DbRecordUpdCurrency) and re-retrieve next records and corresponding
- currency tables (using DbRecordGetCurrency) until the window is
- full.
-
-
- Updating a current record
-
- An update, like the delete described above, can create similar
- problems. This is only a problem if the key field that was used
- for the retrieval of records is updated. In this case, the slots
- could be rearranged in an order unknown to the calling application.
- The only way to solve this problem, is to re-retrieve the records
- and their associated currency tables from the beginning after the
- update takes place.
-
-
- DATABASE INTERNALS
-
-
- Memory Requirements
-
- CDB requires a very small amount of memory to operate. The
- library allocates all memory required for data access and
- manipulation during the DbOpen call. Memory is NOT allocated by
- the database during the execution of any other database call.
-
- CDB will consume approximately 45K of code and data space. A
- portion of this space is allocated when a database is opened. A
- variable amount of memory is also allocated and depends upon the
- size of the DBD file. This space is used for DBD record, owner,
- member, and field tables. To calculate the variable amount of
- memory that will be required by a DBD, use the following formula:
-
- DBD memory consumption = (number of records * 46) +
- (number of owners * 4) + (number of members * 8) +
- (number of fields * 40)
-
- The DBDLIST utility included in this release will display the
- number of records, owners, members, and fields in a DBD. As an
- example, the SAMPLEDB.DBD displayed in this document will consume
- only 590 bytes for the tables described above.
-
-
- Database Files
-
- Database records are organized in data and key files. Each record
- type defined in the DDL will have an associated data file. If any
- key fields exist in this record, the record type will also have a
- key file. Key files have a .key extension while data files have a
- .dat extension.
-
-
- File Naming
-
- /* sampledb.ddl */
-
- prefix ABC;
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char state[3];
- key char zip[11];
- key char telephone[13];
- char fax[13];
- };
-
- struct setup
- {
- key long nextclientnbr;
- };
-
- Key and data files are not created until the first record of a
- specific record type is added. For example, when the first
- 'client' record is added to the database, a data and key file will
- be created. The names used for the .DAT and .KEY file are derived
- as follows:
-
- sprintf( keyfile, "%s%4.4d", prefix, orderinDBD);
- sprintf( datfile, "%s%4.4d", szPrefix, orderinDBD);
-
- The prefix is the prefix defined in the DDL. In our example, the
- prefix is "ABC". The orderinDBD is the record number in the
- database definition (.DBD) file. When DDLP compiles the DDL into
- DBD format, record tables are stored describing each record
- structure definition. The record tables are stored in alphabetical
- order in the DBD file. In our example, the record order in the DBD
- is 'address', 'client', then 'setup'. Therefore, when the first
- 'client' record is added to the database, ABC0001.DAT and
- ABC0001.KEY are created. When the first 'address' record is added,
- ABC0000.DAT and ABC0000.KEY are created.
-
- If a record definiton does not contain a key field, a key file is
- not created for this record.
-
-
- Key File Layout
-
- Key files are organized as a series of pages. Pages contain a
- series of slots. The slots contain the key data. Slots on a page
- are in sorted order. A key file will contain pages of keys for a
- specific record type. For example, in SAMPLEDB.DDL shown above,
- the 'client' key file will contain pages of keys for the 'client'
- record.
-
- Some pages will contain client numbers and some pages will contain
- client names. A page will not contain both client numbers and
- client names.
-
- The key file structures are listed below:
-
- struct key_file_index
- {
- CHAR name[12]; /* Key file name */
- UINT nextavailpage; /* Next available page */
- UINT firstdelpage; /* First page in the delete */
- /* chain. */
- UINT pagenbr[MAXKEY];/* Key 1st page index */
- };
-
- This structure is included at the beginning of every key file. It
- contains necessary pointers for finding the next available page,
- first deleted page in the delete chain, and the first page for
- each key field defined in the record.
-
- struct key_page_index
- {
- UINT prevpage; /* Previous page in sort tree */
- UINT nextpage; /* Next page in sort tree */
- UINT slotsused; /* Number of slots used on page */
- UINT slotsize; /* Size of key slot */
- UINT flags; /* Bit 0 - page is full */
- };
-
- This structure is included at the beginning of each page in the
- key file. The slots in the key file consist of nothing but raw
- key field data.
-
-
- Data File Layout
-
- Data files do not contain pages. They are organized as a series
- of slots in a file. Pages are not needed here because data files
- contain only record data. They are indexed by their respective
- key files.
-
- The data file structures are listed below:
-
- struct data_file_index
- {
- CHAR name[12]; /* Data file name */
- ULONG nextavailslot; /* Next available slot */
- ULONG firstdelslot; /* First slot in the delete */
- /* chain. */
- UINT slotsize; /* Size of data slot */
- CHAR filler[10];
- };
-
- This structrure is included at the beginning of every data file.
- It contains necessary pointers for finding the next available slot,
- first deleted slot in the delete chain, and the data slot size.
-
- struct data_slot_index
- {
- UINT offsettodata; /* Offset to actual data */
- ULONG nextdel; /* DBA of next member in the */
- /* delete chain. */
- };
-
- This structure is included at the beginning of each data slot. A
- data slot also contains owner and/or member data if the record type
- is an owner of or member of another record. The owner and member
- pointer tables are not shown here. In summary, a data slot
- contains a data_slot_index, owner data tables, member data table,
- followed by the actual data record.
-
-
- Modifying Internal Definitions
-
- It is relatively easy to change some of the global definitions
- used CDB. In some extreme cases, modification may be necessary.
- This, of course, depends on your database model (data definition
- file). Source code is required to make any of the changes to the
- definitions listed below.
-
- All definitions described are included in DBMGR.H.
-
-
- #define NBRHANDLES 12
-
- This value is the number of database files that can be open at
- one time. A data file exists for every record defined in the DDL
- if at least one record of that type has been added. If the DDL
- structure definition contains one or more key fields, a key file
- will also be created.
-
- struct client
- {
- key long lClientNbr;
- key char szName[31];
- char szDescription[61];
- double dBalance;
- };
-
- In this DDL example, two files will be created when the first
- record of this type is added to the database. A data file will
- be created and because at least 1 key field exists, a key file
- will also be created.
-
- CDB uses an LRU (least recently used) algorithm to manage
- database file handles. If CDB needs to open a file and 12
- database files are already open, CDB closes the least recently
- used handle and proceeds to open the new file. The new file
- handle is then placed in the LRU table.
-
- If your database model contains more than 12 database files,
- database perfomance may be enhanced by increasing the NBRHANDLES
- value. Note: The maximum number of file handles available for a
- single task under DOS is 20. 5 are reserved for internal use.
- If you leave NBRHANDLES defined as 12, only 3 are available for
- your application.
-
-
- #define MAXKEY 8
-
- This value is the maximum number of key fields that a single
- record definition can contain. Increase this value only if you
- have more than 8 key fields defined in a single record definition.
-
-
- #define KEYPAGESIZE 512
-
- Key fields are stored in sorted order in slots on pages. A key
- file is made up of a header and a series of these pages.
- KEYPAGESIZE is the size of a key page. If your database key
- fields are very large, you might increase the performance of the
- database by increasing this value. If modified, KEYPAGESIZE
- should be a multiple of the average key field length. Note:
- The larger the key page size, the longer the access time for
- reads and writes.
-
-
- #define NBRPAGES 16
-
- This value is the number of key pages that are buffered in RAM
- by CDB. These buffers are managed using an LRU (least recently
- used) algorithm for maximum efficiency.
-
-
- #define DATAPAGESIZE 2048
-
- Data records are stored in slots on pages. The pages are stored
- in the data file (.DAT). This value is the size of the data pages.
- It is recommended that this value be a power of 2.
-
-
- #define DATASLOTSIZE 1024
-
- This value is the maximum size of a data slot. A data slot
- contains a small header, followed by owner tables (if any),
- followed by member tables (if any), followed by the actual data.
- You will need to increase this value if your record sizes, when
- plugged into the formula below, exceed 1024.
-
- Formula:
-
- 6 +
- (number of member record types this record can own * 8) +
- (number of owner record types that can own this record * 12) +
- C structure length (in bytes)
-
- If you have very large C structures you should check them. It is
- recommended that DATASLOTSIZE be a power of 2.
-
-
- Example:
-
- /* sampledb.ddl */
-
- struct client
- {
- connect address key street;
- key long clientnbr;
- key char name[31];
- char description[61];
- double balance;
- };
-
- struct address
- {
- char street[31];
- char city[21];
- char state[3];
- key char zip[11];
- key char telephone[13];
- char fax[13];
- };
-
- In this DDL example, the size of a 'client' data slot would be:
-
- 6 +
- (1 * 8) +
- (0 * 12) +
- 104 = 118
-
- The size of an 'address' data slot would be:
-
- 6 +
- (0 * 8) +
- (1 * 12) +
- 92 = 110
-
-
- UTILITIES
-
-
- DDLP.EXE
-
- DDLP is the Data Definition Language Parser (compiler). It reads
- the DDL file and creates a binary database definition file with a
- .DBD extenstion. DDLP also creates a C header file with a .H
- extension.
-
- The DBD file name is used with the DbOpen function call. The
- DbOpen function passes the DBD file name as a parameter. The DBD
- file is read into memory by CDB and serves as a roadmap for the
- database.
-
- The maximum size of a .DDL file that DDLP can process is 65535
- bytes. A complete list of DDLP error messages are provided in the
- 'Error Messages' section in this manual.
-
-
- Syntax:
-
- DDLP filename(.ddl)
-
-
- Example:
-
- DDLP sampledb.ddl
-
- In this example, DDLP will create SAMPLEDB.DBD and SAMPLEDB.H if
- the compilation is successful.
-
-
- DBDLIST.EXE
-
- DBDLIST displays the contents of the binary database definition
- file (.DBD) created by DDLP. A header, record definitions, owner
- definitions, member definitions, and field definitions are
- displayed.
-
- DBDLIST does not display the contents of any data or key files.
-
-
- Syntax:
-
- DBDLIST filename.dbd
-
-
- Example:
-
- DBDLIST sampledb.dbd
-
-
- USING THE C-API
-
-
- Introduction
-
- The CDB C-API library is callable from both C and C++ modules.
- Over 30 functions are available. Function prototypes are defined
- in DBMGR.H.
-
-
- Functions by Category
-
- Database Management
-
- DbClose Close a database.
- DbFlush Flush all data files to disk.
- DbOpen Open a database.
-
-
- Record Management
-
- DbRecordAdd Add a record.
- DbRecordDelete Delete a record.
- DbRecordUpdate Update a record.
-
-
- Record Find
-
- DbRecordFindByKey Find a record by key value.
- DbRecordFindFirst Find the first record.
- DbRecordFindLast Find the last record.
- DbRecordFindNext Find the next record.
- DbRecordFindPrev Find the previous record.
-
-
- Record Retrieval
-
- DbRecordGetByKey Get a record by key value.
- DbRecordGetCurrent Get the current record.
- DbRecordGetFirst Get the first record.
- DbRecordGetLast Get the last record.
- DbRecordGetNext Get the next record.
- DbRecordGetPrev Get the previous record.
-
-
- Record Currency
-
- DbRecordGetCurrency Get the currency table of a record type.
- DbRecordUpdCurrency Update the currency table of a record type.
-
-
- Set Management
-
- DbSetAdd Make a set connection between two records.
- DbSetDelete Remove a set connection between two records.
-
-
- Set Find
-
- DbSetFindFirst Find the first member record in an
- owner/member relationship.
- DbSetFindLast Find the last member record in an
- owner/member relationship.
- DbSetFindNext Find the next member record in an
- owner/member relationship.
- DbSetFindPrev Find the previous member record in an
- owner/member relationship.
-
-
- Set Retrieval
-
- DbSetGetFirst Get the first member record in an
- owner/member relationship.
- DbSetGetLast Get the last member record in an
- owner/member relationship.
- DbSetGetNext Get the next member record in an
- owner/member relationship.
- DbSetGetOwner Get the owner record of a member in an
- owner/member relationship.
- DbSetGetPrev Get the previous member record in an
- owner/member relationship.
-
-
- DbClose
- -------
-
- Summary
-
- INT DbClose( void);
-
-
- Description
-
- The DbClose function closes the open database. All database
- files are closed and memory is deallocated.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS. See the 'Error Messages' section for more detail
- on this value.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
-
- if( status = DbOpen( ".\\", "test.dbd"))
- {
- /* Database not opened */
- }
-
- /* Other CDB calls... */
-
- if( status = DbClose())
- {
- /* Database not closed */
- }
- }
-
-
- DbFlush
- -------
-
- Summary
-
- INT DbFlush();
-
-
- Description
-
- The DbFlush function forces all data written to the database to
- disk. Dirty memory pages are written to disk and all open files
- are closed and then reopened.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS. See the 'Error Messages' section for more detail
- on this value.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function( struct client far *pClient)
- {
- INT status;
-
- if( status = DbRecordUpdate( "client", pClient))
- {
- /* Record not updated */
- }
-
- if( status = DbFlush())
- {
- /* Database not flushed */
- }
- }
-
-
- DbOpen
- ------
-
- Summary
-
- INT DbOpen( char *pDbDir, char *pDbName)
-
-
- Parameters
-
- pDbDir CHAR * Identifies the directory where CDB will
- attempt to open the .DBD (Database Definition)
- file. CDB will also attempt to open and/or create
- all associated database files in this directory.
- If NULL, CDB will use the current directory.
- Note: If a directory name is present, it must
- end with a backslash. e.g. "C:\\PRODUCTA\\".
-
- pDbName CHAR * Identifies the .DBD (Database Definition)
- file.
-
-
- Description
-
- The DbOpen function opens a CDB database. The database definition
- file (pDbName) is created by DDLP.EXE.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS. See the 'Error Messages' section for more detail
- on this value.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
-
- if( status = DbOpen( "C:\\PRODUCTA\\", "test.dbd"))
- {
- /* Error opening database */
- }
-
- /* Other CDB calls... */
- }
-
-
- DbRecordAdd
- -----------
-
- Summary
-
- INT DbRecordAdd( CHAR *pRecName, VOID *pData)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pData VOID * Pointer to the record data.
-
-
- Description
-
- The DbRecordAdd function adds a record to the database.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS or E_NORECNAME. See the 'Error Messages' section
- for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- INT Function( CHAR *pClientData)
- {
- INT status;
-
- if( status = DbRecordAdd( "client", pClientData))
- {
- /* Error adding record */
- }
-
- return status;
- }
-
-
- DbRecordDelete
- --------------
-
- Summary
-
- INT DbRecordDelete( CHAR *pRecName)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
-
- Description
-
- The DbRecordDelete function deletes a record from the database.
- The record deleted is the current record of the pRecName type.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error
- Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- if( status = DbRecordDelete( "client"))
- {
- /* Error deleting record */
- }
- }
-
-
- DbRecordFindByKey
- -----------------
-
- Summary
-
- INT DbRecordFindByKey( CHAR *pRecName, CHAR *pFldName, VOID *pKey)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pKey VOID * Pointer to the key data to be used for the
- record search.
-
-
- Description
-
- The DbRecordFindByKey function searches for a specific record
- using a key field and key value.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND, or
- E_NEXTGUESS. See the 'Error Messages' section for more detail on
- these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- if( status = DbRecordFindByKey( "client", "lClientNbr",
- &clientnbr))
- {
- /* Record not found */
- }
- }
-
-
- DbRecordFindFirst
- -----------------
-
- Summary
-
- INT DbRecordFindFirst( CHAR *pRecName, CHAR *pFldName)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
-
- Description
-
- The DbRecordFindFirst function sets the database currency to the
- first logical record sorted by pFldName. For more on currency,
- see the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
-
- /* Delete all client records in database */
- while( ! DbRecordFindFirst( "client", "clientnbr"))
- {
- if( status = DbRecordDelete( "client"))
- {
- /* Error deleting record */
- }
- }
- }
-
-
- DbRecordFindLast
- ----------------
-
- Summary
-
- INT DbRecordFindLast( CHAR *pRecName, CHAR *pFldName)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
-
- Description
-
- The DbRecordFindLast function sets the database currency to the
- last logical record sorted by pFldName. For more on currency, see
- the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
-
- /* Delete all client records in database */
- while( ! DbRecordFindLast( "client", "clientnbr"))
- {
- if( status = DbRecordDelete( "client"))
- {
- /* Error deleting record */
- }
- }
- }
-
-
- DbRecordFindNext
- ----------------
-
- Summary
-
- INT DbRecordFindNext( CHAR *pRecName, CHAR *pFldName)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
-
- Description
-
- The DbRecordFindNext function sets the database currency to the
- next logical record sorted by pFldName. The record must have
- currency before this call is executed. For more on currency, see
- the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
- E_NOCURRENT, or E_NONEXT. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- INT Function()
- {
- /* Down arrow key pressed, check for next */
- /* record in database. */
- return( DbRecordFindNext( "client", "clientnbr"));
- }
-
-
- DbRecordFindPrev
- ----------------
-
- Summary
-
- INT DbRecordFindPrev( CHAR *pRecName, CHAR *pFldName)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
-
- Description
-
- The DbRecordFindPrev function sets the database currency to the
- previous logical record sorted by pFldName. The record must have
- currency before this call is executed. For more on currency, see
- the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
- E_NOCURRENT, or E_NOPREV. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- INT Function()
- {
- /* Up arrow key pressed, check for previous */
- /* record in database. */
- return( DbRecordFindPrev( "client", "clientnbr"));
- }
-
-
- DbRecordGetByKey
- ----------------
-
- Summary
-
- INT DbRecordGetByKey( CHAR *pRecName, CHAR *pFldName, VOID *pTarget,
- VOID * pKey)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
- pKey VOID * Pointer to the key data.
-
-
- Description
-
- The DbRecordGetByKey function retrieves a record using a key value.
- If the exact match cannot be found the function will return
- E_NEXTGUESS specifying that the data returned is the next best
- guess.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND, or
- E_NEXTGUESS. See the 'Error Messages' section for more detail on
- these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG key = 1000L;
- CLIENT client;
-
- /* Get client record with client number equal 1000L */
- if( status = DbRecordGetByKey( "client", "clientnbr", &client,
- &key))
- {
- /* Client not retrieved */
- }
- }
-
-
- DbRecordGetCurrency
- -------------------
-
- Summary
-
- INT DbRecordGetCurrency( CHAR *pRecName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pTarget VOID * Pointer to the storage area for the currency
- information.
-
-
- Description
-
- The DbRecordGetCurrency function retrieves the current currency
- table for a specific record. For more on currency, see the
- Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, or E_NORECNAME. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- struct currency_index currency;
-
- /* Get the currency for the client record */
- if( status = DbRecordGetCurrency( "client", ¤cy))
- {
- /* Currency not retrieved */
- }
-
- /* Other processing goes here... */
-
- /* Restore the currency for the client record */
- if( status = DbRecordUpdCurrency( "client", ¤cy))
- {
- /* Currency not updated */
- }
- }
-
-
- DbRecordGetCurrent
- ------------------
-
- Summary
-
- INT DbRecordGetCurrent( CHAR *pRecName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbRecordGetCurrent function retrieves the record that has
- currency (or 'is current') for that record type (record name).
- Each record type has its own currency table. For more on currency,
- see the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error Messages'
- section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
- CLIENT client;
-
- /* Check for client #1000 */
- if( status = DbRecordFindByKey( "client", "lClientNbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Retrieve it */
- if( status = DbRecordGetCurrent( "client", &client))
- {
- /* Record not retrieved */
- }
- }
-
-
- DbRecordGetFirst
- ----------------
-
- Summary
-
- INT DbRecordGetFirst( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbRecordGetFirst function retrieves the first record by the
- key field passed. After this call, the currency for this record
- type is set to the first record.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Get the first record sorted by client number*/
- if( status = DbRecordGetFirst( "client", "clientnbr", &client))
- {
- /* Record not retrieved */
- }
- }
-
-
- DbRecordGetLast
- ---------------
-
- Summary
-
- INT DbRecordGetLast( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbRecordGetLast function retrieves the last record by the key
- field passed. After this call, the currency for this record type
- is set to the last record.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Get the last record sorted by client number*/
- if( status = DbRecordGetLast( "client", "clientnbr", &client))
- {
- /* Record not retrieved */
- }
- }
-
-
- DbRecordGetNext
- ---------------
-
- Summary
-
- INT DbRecordGetNext( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbRecordGetNext function retrieves the next record by the key
- field passed. After this call, the currency for this record type
- is set to the record retrieved.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
- E_NOCURRENT, or E_NONEXT. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Get the next record sorted by client number*/
- if( status = DbRecordGetNext( "client", "clientnbr", &client))
- {
- /* Record not retrieved */
- }
- }
-
-
- DbRecordGetPrev
- ---------------
-
- Summary
-
- INT DbRecordGetPrev( CHAR *pRecName, CHAR *pFldName, VOID *pTarget)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pFldName CHAR * Pointer to the field name. Must be a key
- field.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbRecordGetPrev function retrieves the previous record by the
- key field passed. After this call, the currency for this record
- type is set to the record retrieved.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_NOFLDNAME, E_NOTAKEY, E_NOTFOUND,
- E_NOCURRENT, or E_NOPREV. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Get the previous record sorted by client number*/
- if( status = DbRecordGetPrev( "client", "clientnbr", &client))
- {
- /* Record not retrieved */
- }
- }
-
-
- DbRecordUpdate
- --------------
-
- Summary
-
- INT DbRecordUpdate( CHAR *pRecName, VOID *pData)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pData VOID * Pointer to the updated record data.
-
-
- Description
-
- The DbRecordUpdate function updates a database record. The record
- to be updated must be current. For more on currency, see the
- Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, or E_NOCURRENT. See the 'Error Messages'
- section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Get the first record */
- if( status = DbRecordGetFirst( "client", "clientnbr", &client))
- {
- /* Record not retrieved */
- }
-
- /* Modify input logic goes here... */
-
- /* Update the record */
- if( status = DbRecordUpdate( "client", &client))
- {
- /* Error updating record */
- }
- }
-
-
- DbRecordUpdCurrency
- -------------------
-
- Summary
-
- INT DbRecordUpdCurrency( CHAR *pRecName, VOID *pData)
-
-
- Parameters
-
- pRecName CHAR * Pointer to the record name.
-
- pData VOID * Pointer to the storage area for the currency
- information.
-
-
- Description
-
- The DbRecordUpdCurrency function updates the currency for a
- specific record type. For more on currency, see the Database
- Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS or E_NORECNAME. See the 'Error Messages' section for
- more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- struct currency_index currency;
-
- /* Get the currency for the client record */
- if( status = DbRecordGetCurrency( "client", ¤cy))
- {
- /* Error retrieving currency */
- }
-
- /* Other processing goes here... */
-
- /* Restore the currency for the client record */
- if( status = DbRecordUpdCurrency( "client", ¤cy))
- {
- /* Error updating currency */
- }
- }
-
-
- DbSetAdd
- --------
-
- Summary
-
- INT DbSetAdd( CHAR *pOwnerName, CHAR *pMemberName)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetAdd function makes a set connection between two records.
- Both records must have currency before making the call.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, or E_NOCURRENT. See the
- 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
-
- /* Add an client record */
- /* Assuming 'sclient' is global and structure prefilled */
- if( status = DbRecordAdd( "client", &sclient))
- {
- /* Error adding record */
- }
-
- /* Add an address record */
- /* Assuming 'saddress' is global and structure prefilled */
- if( status = DbRecordAdd( "address", &saddress))
- {
- /* Error adding record */
- }
-
- /* Make a set connection between records */
- /* After this call, the 'client' record is the owner of the */
- /* 'address' record */
- /* The 'address' record is a member of the 'client' record */
- if( status = DbSetAdd( "client", "address"))
- {
- /* Error making set connection */
- }
- }
-
-
- DbSetDelete
- -----------
-
- Summary
-
- INT DbSetDelete( CHAR *pOwnerName, CHAR *pMemberName)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetDelete function removes a set connection between two
- records. Both records must have currency before making the call.
- This function does not delete either record, it only removes the
- connection between the two.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, or E_NOCURRENT. See the
- 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Set the currency for the address record to the first */
- /* member of the client record */
- if( status = DbSetFindFirst( "client", "address"))
- {
- /* First member not found */
- }
-
- /* Delete the owner/member set connection */
- if( status = DbSetDelete( "client", "address"))
- {
- /* Error deleting record */
- }
- }
-
-
- DbSetFindFirst
- --------------
-
- Summary
-
- INT DbSetFindFirst( CHAR *pOwnerName, CHAR *pMemberName)
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetFindFirst function sets the database currency for the
- member record to the first member in the owner/member set relation.
- The owner record must have currency before this call. For more on
- currency, see the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Set the currency for the address record to the first */
- /* member of the client record */
- if( status = DbSetFindFirst( "client", "address"))
- {
- /* First member not found */
- }
- }
-
-
- DbSetFindLast
- -------------
-
- Summary
-
- INT DbSetFindLast( CHAR *pOwnerName, CHAR *pMemberName)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetFindLast function sets the database currency for the
- member record to the last member in the owner/member set relation.
- The owner record must have currency before this call. For more on
- currency, see the Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Set the currency for the address record to the last */
- /* member of the client record */
- if( status = DbSetFindLast( "client", "address"))
- {
- /* Last member not found */
- }
- }
-
-
- DbSetFindNext
- -------------
-
- Summary
-
- INT DbSetFindNext( CHAR *pOwnerName, CHAR *pMemberName)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetFindNext function sets the database currency for the
- member record to the next member in the owner/member set relation.
- Both owner and member records must have currency before this call.
- For more on currency, see the Database Currency section in this
- manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NONEXT.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Set the currency for the address record to the first */
- /* member of the client record */
- if( status = DbSetFindFirst( "client", "address"))
- {
- /* First member not found */
- }
-
- /* Set the currency for the address record to the next member */
- /* of the client record */
- if( status = DbSetFindNext( "client", "address"))
- {
- /* Next member not found */
- }
- }
-
-
- DbSetFindPrev
- -------------
-
- Summary
-
- INT DbSetFindPrev( CHAR *pOwnerName, CHAR *pMemberName)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
-
- Description
-
- The DbSetFindPrev function sets the database currency for the
- member record to the previous member in the owner/member set
- relation. Both owner and member records must have currency
- before this call. For more on currency, see the Database Currency
- section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOPREV.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Set the currency for the address record to the last */
- /* member of the client record */
- if( status = DbSetFindLast( "client", "address"))
- {
- /* Last member not found */
- }
-
- /* Set the currency for the address record to the previous */
- /* member of the client record */
- if( status = DbSetFindPrev( "client", "address"))
- {
- /* Previous member not found */
- }
- }
-
-
- DbSetGetFirst
- -------------
-
- Summary
-
- INT DbSetGetFirst( CHAR *pOwnerName, CHAR *pMemberName,
- VOID *pTarget)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbSetGetFirst function retrieves the first member of an
- owner/member set relation. The owner record must have currency
- before this call. For more on currency, see the Database Currency
- section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
- ADDRESS address;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Get the first address record */
- if( status = DbSetGetFirst( "client", "address", &address))
- {
- /* First member not found */
- }
- }
-
-
- DbSetGetLast
- ------------
-
- Summary
-
- INT DbSetGetLast( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbSetGetLast function retrieves the last member of an
- owner/member set relation. The owner record must have currency
- before this call. For more on currency, see the Database Currency
- section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOTFOUND.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
- ADDRESS address;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Get the last address record */
- if( status = DbSetGetLast( "client", "address", &address))
- {
- /* Last member not found */
- }
- }
-
-
- DbSetGetNext
- ------------
-
- Summary
-
- INT DbSetGetNext( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbSetGetNext function retrieves the next member of an
- owner/member set relation. Both owner and member records must
- have currency before this call. For more on currency, see the
- Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NONEXT.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
- ADDRESS address;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Get the first address record */
- if( status = DbSetGetFirst( "client", "address", &address))
- {
- /* First member not found */
- }
-
- /* Get the next address record */
- if( status = DbSetGetNext( "client", "address", &address))
- {
- /* Next member not found */
- }
- }
-
-
- DbSetGetOwner
- -------------
-
- Summary
-
- INT DbSetGetOwner( CHAR *pOwnerName, CHAR *pMemberName,
- VOID *pTarget)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbSetGetOwner function retrieves the owner record of a member
- record set relation. The member record must have currency before
- this call. For more on currency, see the Database Currency section
- in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOOWNER.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- CLIENT client;
-
- /* Set the currency to the first invoice record */
- if( status = DbRecordFindFirst( "invoice", "invoicenbr"))
- {
- /* Invoice not found */
- }
-
- /* Get the client record for this invoice */
- if( status = DbSetGetOwner( "client", "invoice", &client))
- {
- /* Client record not found */
- }
- }
-
-
- DbSetGetPrev
- ------------
-
- Summary
-
- INT DbSetGetPrev( CHAR *pOwnerName, CHAR *pMemberName, VOID *pTarget)
-
-
- Parameters
-
- pOwnerName CHAR * Pointer to the owner record name.
-
- pMemberName CHAR * Pointer to the member record name.
-
- pTarget VOID * Pointer to the storage area for the record
- data.
-
-
- Description
-
- The DbSetGetPrev function retrieves the previous member of an
- owner/member set relation. Both owner and member records must
- have currency before this call. For more on currency, see the
- Database Currency section in this manual.
-
-
- Return Value
-
- A 0 is returned if no error occurred. Otherwise the return code
- can be E_DOS, E_NORECNAME, E_INVALIDSET, E_NOCURRENT, or E_NOPREV.
- See the 'Error Messages' section for more detail on these values.
-
-
- Example
-
- #include "dbmgr.h"
-
- void Function()
- {
- INT status;
- LONG clientnbr = 1000L;
- ADDRESS address;
-
- /* Set the currency to client record #1000 */
- if( status = DbRecordFindByKey( "client", "clientnbr",
- &clientnbr))
- {
- /* Record not found */
- }
-
- /* Get the last address record */
- if( status = DbSetGetLast( "client", "address", &address))
- {
- /* Last member not found */
- }
-
- /* Get the previous address record */
- if( status = DbSetGetPrev( "client", "address", &address))
- {
- /* Previous member not found */
- }
- }
-
-
- ERROR MESSAGES
-
- This section describes error messages that you may encounter when
- developing a program using CDB.
-
-
- CDB Run-Time Error Messages
-
- The CDB C-API function calls return an INT value indicating the
- success or failure of a particular database call. A 0 is returned
- if the function was a success. A non-zero value is returned if an
- error occured.
-
- The following list displays the possible error codes that can be
- returned and a brief explanation of each.
-
-
- Error Code Description
-
- E_TESTDRIVE You are using a 'Test Drive' version of CDB.
- The 'Test Drive' version limits the number
- of records that can be added to a database
- to 50.
-
- E_INVALIDCASE Contact Daytris technical support. An
- internal switch statement does not contain
- a valid case. You should never see this
- error code.
-
- E_DOS An MS-DOS error has occured. The global
- 'errno' value contains the specific DOS
- error number. See ERRNO.H and/or the
- Microsoft C documentation for more
- information.
-
- E_NORECNAME The record name passed, pRecName, is not a
- valid record type.
-
- E_NOFLDNAME The field name passed, pFldName, is not a
- valid field for the record.
-
- E_INVALIDSET The owner and member names passed to the
- function do not have a set relationship
- between the two. To create a set
- relatiionship between two records, use the
- CONNECT keyword in the DDL file.
-
- E_NOTAKEY The field name passed to the function is
- not a key field in the record. Use the KEY
- keyword in the DDL file to define key
- fields.
-
- E_NOTFOUND The record was not found.
-
-
- E_NEXTGUESS The record was not found, but the next
- closest match to the key value passed was
- found. If a DbRecordFindByKey call was
- made, currency is set to this 'next guess'
- record. If a DbRecordGetByKey call was
- made, the 'next guess' record is returned.
-
- E_NOCURRENT There is no current record for the record
- name specified. e.g. This error value
- will be returned if a DbRecordGetNext call
- is made before the record requested has
- currency. One way to set currency in this
- case would be to make a DbRecordFindFirst
- call. There are a number of other cases
- where this error code could be returned.
-
- E_NONEXT The next record was not found. e.g.
- DbRecordGetNext(...).
-
- E_NOPREV The previous record was not found. e.g.
- DbRecordGetPrevious(...).
-
- E_NOOWNER This error can only occur with a
- DbSetGetOwner call. If an owner record is
- not found, this value is returned.
-
-
- DDLP Error Messages
-
- The following lists contain a description of error and warning
- messages that may be encountered during the execution of the Data
- Definition Language Parse utility (DDLP.EXE):
-
- Error Number Description
-
- 100 Unexpected end of file reached.
- 101 Unexpected token. DDLP breaks the DDL file into
- tokens. A token can be a bracket, keyword,
- semicolon, variable, constant, etc. It combines the
- tokens and matches them against predefined patterns.
- If a pattern has no match, this error is returned.
- 102 Expecting semicolon.
- 103 Expecting "struct" keyword. DDLP is expecting a
- structure definition to begin.
- 104 Expecting identifier. An identifer can be a
- structure name or field name.
- 105 Expecting '{'. Expecting a left brace.
- 106 Constant too big. A constant is a number. The
- maximum constant size allowed is 10 digits.
- 107 Structure already defined.
- 108 Invalid constant. The interpreted value of the
- constant is zero.
- 109 Maximum size of a constant is 65535.
- 110 Maximum size of a field is 65535.
- 111 Maximum size of a record is 65535.
- 112 Connection already made to 'record name'. You
- cannot to the same record more than once.
- 113 Record does not exist. This error will occur when
- you try to CONNECT to a record that is not defined
- within the DDL file.
- 114 Cannot connect structure to itself.
- 115 Connect key field not found. If you are ordering
- the sets using the 'CONNECT record_name KEY
- key_field_name' convention, the key_field_name is
- not found within the record_name structure
- definition in the DDL file.
-
- Warning Number Description
-
- 100 "prefix" not defined, assuming "test". The PREFIX
- keyword was not used to define the prefix used to
- derive database file names. A "test" prefix is
- used as a default.
- 101 Prefix too long, truncating to 'identifier'. The
- maximum length of a PREFIX is 5 characters.
- 102 Identifier too long. The maximum length of an
- identifier is 31 characters. Extra characters will
- be truncated.
-
- ----------------end-of-author's-documentation---------------
-
- Software Library Information:
-
- This disk copy provided as a service of
-
- Public (software) Library
-
- We are not the authors of this program, nor are we associated
- with the author in any way other than as a distributor of the
- program in accordance with the author's terms of distribution.
-
- Please direct shareware payments and specific questions about
- this program to the author of the program, whose name appears
- elsewhere in this documentation. If you have trouble getting
- in touch with the author, we will do whatever we can to help
- you with your questions. All programs have been tested and do
- run. To report problems, please use the form that is in the
- file PROBLEM.DOC on many of our disks or in other written for-
- mat with screen printouts, if possible. PsL cannot debug pro-
- programs over the telephone, though we can answer questions.
-
- Disks in the PsL are updated monthly, so if you did not get
- this disk directly from the PsL, you should be aware that the
- files in this set may no longer be the current versions. Also,
- if you got this disk from another vendor and are having prob-
- lems, be aware that some files may have become corrupted or
- lost by that vendor. Get a current, working disk from PsL.
-
- For a copy of the latest monthly software library newsletter
- and a list of the 3,000+ disks in the library, call or write
-
- Public (software) Library
- P.O.Box 35705 - F
- Houston, TX 77235-5705
-
- Orders only:
- 1-800-2424-PSL
- MC/Visa/AmEx/Discover
-
- Outside of U.S. or in Texas
- or for general information,
- Call 1-713-524-6394
-
- PsL also has an outstanding
- catalog for the Macintosh.
-
-